﻿using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Workflow_Core_API.Persisted;
using WorkflowCore.Interface;
using WorkflowCore.Models;
using WorkflowCore.Service.Dto.Fundamentals;
using WorkflowCore.Service.Dto.Input;
using WorkflowCore.Service.Persisted;

namespace WorkflowCore.Service.Strps
{
    public class AgreeStep : StepBody
    {
        private readonly GetWorkflowCoreUserData getWorkflowCoreUserData;
        private readonly WorkflowCoreDbcontext dbcontext;

        public AgreeStep(GetWorkflowCoreUserData getWorkflowCoreUserData, WorkflowCoreDbcontext dbcontext)
        {
            this.getWorkflowCoreUserData = getWorkflowCoreUserData;
            this.dbcontext = dbcontext;
        }

        // 当审批通过时执行的步骤
        public override ExecutionResult Run(IStepExecutionContext context)
        {
            List<PersonNode> Users = getWorkflowCoreUserData.ShoWorkflowCoreUserData();
            var eventData = context.Item as WorkflowAuditInput;
            Console.WriteLine($"{Users.First(p => p.UserId == eventData.UserId).UserName} 审批通过");

            // 获取流程设计
            var def = dbcontext.persistedWorkflowDefinition.First(p =>
                p.WorkflowDefinitionId == context.Workflow.WorkflowDefinitionId);
            var stepNodes = JsonConvert.DeserializeObject<List<WorkflowStepNodeInput>>(def.StepNodes);
            var currentStep = stepNodes.First(p => p.StepId == context.Step.ExternalId.Split('@')[0]);

            // 任意一人审批通过
            if (currentStep.Detail?.HandleCountersignType == HandleCountersignTypeEnum.AnyOne)
            {
                ClearWait(context);
            }
            // 超过半数则进入下一步骤
            else if (currentStep.Detail?.HandleCountersignType == HandleCountersignTypeEnum.Half)
            {
                // 查询当前待审批的ExecutePointerId,得知当前审批步骤共有多少人要审批
                // 必须要考虑重新发起情况，这种情况下会有重复StepId
                var waitAudit = dbcontext.persistedWorkflowAuditor
                    .FirstOrDefault(p => p.WorkflowId == context.Workflow.Id
                                         && p.Status == WorkFlowAuditStatus.UnAudited);
                if (waitAudit is not null)
                {
                    var parentPointerId = context.Workflow.ExecutionPointers
                        .FirstOrDefault(p => p.Id == waitAudit.ExecutionPointerId.ToString())!.PredecessorId;
                    // 查询当前步骤所有节点数
                    var currentStepPointers =
                        context.Workflow.ExecutionPointers.Where(p => p.PredecessorId == parentPointerId);
                    // 已经审批数
                    var hasAuditCount = currentStepPointers.Count(p => p.EventPublished);
                    if (hasAuditCount / 1.0 / currentStepPointers.Count() >= 0.5)
                    {
                        ClearWait(context);
                    }
                }
            }

            return ExecutionResult.Next();
        }
        private void ClearWait(IStepExecutionContext context)
        {
            // 1.  取消节点等待审批事件
            var waitPointers = context.Workflow.ExecutionPointers.Where(e =>
                e.Status == PointerStatus.WaitingForEvent && e.EventName == "AuditEvent");
            foreach (var pointer in waitPointers)
            {
                pointer.Status = PointerStatus.Complete;
                pointer.EventPublished = true;
                pointer.EndTime = DateTime.Now;
                pointer.EventKey = string.Empty;
                pointer.EventName = string.Empty;
                pointer.Active = false;

                // 2. 取消事件订阅
                var subscriptions = dbcontext.PersistedSubscription.AsTracking()
                    .Where(p => p.ExecutionPointerId == pointer.Id);
                dbcontext.PersistedSubscription.RemoveRange(subscriptions);
            }

            // 3. 解决流程已经进入了下一节点，但还有待审批的记录问题
            var unAuditList = dbcontext.persistedWorkflowAuditor.AsTracking().Where(p =>
                p.Status == WorkFlowAuditStatus.UnAudited
                && p.WorkflowId == context.Workflow.Id);
            dbcontext.persistedWorkflowAuditor.RemoveRange(unAuditList);

            dbcontext.SaveChanges();
        }
    }
}
